const { src, dest, parallel, series, watch } = require('gulp')

const del = require('del')
const browserSync = require('browser-sync')

const loadPlugins = require('gulp-load-plugins')

const plugins = loadPlugins()
const bs = browserSync.create()

const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html',
    },
    {
      name: 'Features',
      link: 'features.html',
    },
    {
      name: 'About',
      link: 'about.html',
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce',
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme',
        },
        {
          name: 'divider',
        },
        {
          name: 'About',
          link: 'https://github.com/zce',
        },
      ],
    },
  ],
  pkg: require('./package.json'),
  date: new Date(),
}

// 清空文件夹
const clean = () => {
  return del(['dist', 'temp'])
}

const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true })) // 以流的方式往浏览器推，这样bs.init里的files就不需要了
}

const script = () => {
  return src('src/assets/scripts/*.js', { base: 'src' })
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}

// 注意：有时直接修改模板，不会立即热更新，主要是因为swig模板引擎缓存的机制导致页面不会变化
// 此时，需要额外将swig选项中的cache设置为false
const page = () => {
  return src('src/*.html', { base: 'src' })
    .pipe(plugins.swig({ data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}

const image = () => {
  return src('src/assets/images/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

const font = () => {
  return src('src/assets/fonts/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

const extra = () => {
  return src('public/**', { base: 'public' }).pipe(dest('dist'))
}

const serve = () => {
  // 有意义的编译
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // watch('src/assets/images/**', image)
  // watch('src/assets/fonts/**', font)
  // watch('public/**', extra)
  // 在开发阶段一般不会经常改，所以不需要监听以下几个文件
  // 只要在发布上线前，编译一遍就好了
  // 这样开发环境就减少了一起编译
  watch(['src/assets/images/**', 'src/assets/fonts/**', 'public/**'], bs.reload) // 三种文件变化过后，执行reload方法

  bs.init({
    notify: false,
    port: 2080,
    // open: false, // 是否启动时自动打开浏览器
    // files: 'dist/**', // 当服务器启动后，这个文件夹下的文件变化将被监听，改变时自动热更新，不使用files，可以使用bs.reload
    server: {
      // 定义网站根目录，数组的形式，会先找temp，找不到再去src下，找不到再找public
      // 这样得先complie一次，生成图片和字体
      baseDir: ['temp', 'src', 'public'],
      // 加上特殊路由，对于/node_modules的请求，映射到某个文件夹下
      routes: {
        '/node_modules': 'node_modules',
      },
    },
  })
}

// 结果放在dist，构建放在temp，目的是防止读写冲突，写不进文件
const useref = () => {
  return (
    src('temp/*.html', { base: 'temp' }) // 这里找的是打包后的目录下的文件，temp是打包后的文件夹
      .pipe(plugins.useref({ searchPath: ['temp', '.'] })) // 确定注释里面的文件，可以在哪个目录文件找，这里是指定temp文件夹找，找不到就在根目录下找
      // useref处理后会有三种文件类型html js css
      .pipe(plugins.if(/\.js$/, plugins.uglify())) // gulp-if用来判断是哪种类型的文件
      .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
      .pipe(
        plugins.if(
          /\.html$/,
          plugins.htmlmin({
            collapseWhitespace: true, // 自动压缩空白符号和换行符
            minifyCSS: true, // 压缩内敛的css
            minifyJS: true, // 压缩内敛的js
          })
        )
      )
      .pipe(dest('dist'))
  )
}

const compile = parallel(style, script, page)

// 上线之前执行的任务
const build = series(
  clean,
  parallel(series(compile, useref), image, font, extra)
)

const develop = series(compile, serve)

module.exports = {
  clean,
  build,
  develop,
}
